package core.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 工作工具类
 *
 * @author Gong.Yang
 */
@Slf4j
public class WorkUtil {

    private final static String javaFileHead = "public class %s {";
    private final static String model = "@ApiModelProperty(value = \"%s\")\n";
    private final static String strItem = "\n%s\tprivate String %s;";
    private final static String doubleItem = "\n%s\tprivate Double %s;";
    private final static String dateItem = "\n%s\tprivate Date %s;";
    private final static String boolItem = "\n%s\tprivate Boolean %s;";
    private final static String intItem = "\n%s\tprivate Integer %s;";
    private final static String objItem = "\n%s\tprivate %s %s;";
    private final static String arrayItem = "\n%s\tprivate List<%s> %s;";


    interface SqlConstant {
        String createTableRegex = "(?i).*create table .*";
        String filedRegex = "(?i).*(?: TINYINT| SMALLINT| MEDIUMINT| INT| INTEGER| BIGINT| FLOAT| DOUBLE| DECIMAL| CHAR | VARCHAR| TINYTEXT| TEXT| MEDIUMTEXT| LONGTEXT| BINARY| VARBINARY| TINYBLOB| BLOB| MEDIUMBLOB| LONGBLOB| DATE| TIME| DATETIME| TIMESTAMP| YEAR| BOOL| BOOLEAN| ENUM| SET| GEOMETRY| POINT| LINESTRING| POLYGON| MULTIPOINT| MULTILINESTRING| MULTIPOLYGON| GEOMETRYCOLLECTION| JSON).*";
        String strRegex = "(?i).*(?:FLOAT| DOUBLE| DECIMAL| CHAR | VARCHAR| TINYTEXT| TEXT| MEDIUMTEXT| LONGTEXT).*";
        String intRegex = "(?i).*(?: TINYINT| SMALLINT| MEDIUMINT| INT| INTEGER| BIGINT).*";
        String doubleRegex = "(?i).*(?: FLOAT| DOUBLE| DECIMAL).*";
        String boolRegex = "(?i).*(?: BOOL| BOOLEAN).*";
        String dateRegex = "(?i).*(?: DATE| TIME| DATETIME| TIMESTAMP| YEAR).*";

        String commentRegex = "(?i).* comment .*";
    }


    /**
     * 建表sql转Java对象
     *
     * @param outDir  输出路径
     * @param isModel 是不是swagger实体类
     */
    public static void sqlToJava(String createTableSql, String outDir, boolean isModel) {
        String[] lines = createTableSql.split("\n");

        String currentFileName = null;
        StringBuffer currentFileContent = null;

        for (String line : lines) {
            line = line.trim();
            if (line.startsWith("--")) continue;
            if (Pattern.matches(SqlConstant.createTableRegex, line)) {
                System.out.println(line);

                if (!StrUtil.hasBlank(currentFileName, currentFileContent)) {
                    //将上一个文件保存
                    currentFileContent.append("\n}");
                    FileUtil.writeString(currentFileContent.toString(), outDir + currentFileName, StandardCharsets.UTF_8);
                }

                //取出表名，开始下一个文件
                String tableName = line.split("(?i).*create table ")[1].split(" ")[0];
                String className = getHumpName(tableName, true);
                currentFileName = className + ".java";
                currentFileContent = new StringBuffer();
                currentFileContent.append(String.format(javaFileHead, className));
            }
            if (Pattern.matches(SqlConstant.filedRegex, line)) {
                String filedName = getHumpName(line.split(" ")[0], false);
                String comment = "";
                if (isModel) {
                    comment = Pattern.matches(SqlConstant.commentRegex, line) ?
                            line.split("(?i).*comment ")[1].split("'")[1] :
                            filedName;
                    comment = "\t" + String.format(model, comment);
                }
//                System.out.println(comment);
                if (Pattern.matches(SqlConstant.strRegex, line)) {
                    String filed = "\n" + String.format(strItem, comment, filedName);
                    currentFileContent.append(filed);
                    continue;
                }
                if (Pattern.matches(SqlConstant.intRegex, line)) {
                    String filed = "\n" + String.format(intItem, comment, filedName);
                    currentFileContent.append(filed);
                    continue;
                }
                if (Pattern.matches(SqlConstant.dateRegex, line)) {
                    String filed = "\n" + String.format(dateItem, comment, filedName);
                    currentFileContent.append(filed);
                    continue;
                }
                if (Pattern.matches(SqlConstant.boolRegex, line)) {
                    String filed = "\n" + String.format(boolItem, comment, filedName);
                    currentFileContent.append(filed);
                    continue;
                }
                if (Pattern.matches(SqlConstant.doubleRegex, line)) {
                    String filed = "\n" + String.format(doubleItem, comment, filedName);
                    currentFileContent.append(filed);
                    continue;
                }
                String filed = "\n" + String.format(objItem, comment, "Object", filedName);
                currentFileContent.append(filed);

            }
        }

        if (!StrUtil.hasBlank(currentFileName, currentFileContent)) {
            //将上一个文件保存
            currentFileContent.append("\n}");
            FileUtil.writeString(currentFileContent.toString(), outDir + currentFileName, StandardCharsets.UTF_8);
        }

    }

    private static String getHumpName(String str, boolean titleCase) {
        String result = Arrays.stream(str.split("_"))
                .map(s -> s.substring(0, 1).toUpperCase() + s.substring(1)).collect(Collectors.joining());

        return titleCase ? result : result.substring(0, 1).toLowerCase() + result.substring(1);
    }


    /**
     * json字符串 输出 Java类
     *
     * @param json    json字符串
     * @param isModel 是不是swagger实体类
     */
    public static void jsonToJava(String json, boolean isModel, String className) {
        jsonToJava(json, 0, isModel, StrUtil.isBlank(className) ? "Demo0" : className);
    }

    private static String jsonToJava(String json, int num, boolean isModel, String className) {
        className = className.substring(0, 1).toUpperCase() + className.substring(1);

        if (!JSONUtil.isTypeJSON(json)) {
            log.error("【JSONUtil】非json字符串,json->{}", json);
            return null;
        }
        JSONObject jsonObject = JSONUtil.parseObj(json);
        Set<String> keySet = jsonObject.keySet();


        String classTab = StrUtil.repeat("\t", num);


        String classHead = num > 0 ? classTab + "public static class " + className + " {"
                : "public class " + className + " {";
        System.out.println(classHead);
        for (String key : keySet) {
            Object value = jsonObject.get(key);
            outFiled(num, key, value, isModel);
        }
        System.out.println(classTab + "}");
        return className;
    }

    /**
     * 输出字段
     *
     * @param num     嵌套层数
     * @param key     字段名
     * @param value   字段值
     * @param isModel 是否是swagger
     * @return
     */
    private static void outFiled(int num, String key, Object value, boolean isModel) {
        String filedTab = StrUtil.repeat("\t", num + 1);

        String notes = "";
        if (isModel) {
            notes = "@ApiModelProperty(value = \"" + key + "\")\n";
        }

        if (value instanceof String str) {
            System.out.println(filedTab + String.format(strItem, notes, key));
        }
        if (value instanceof BigDecimal bigDecimal) {
            System.out.println(filedTab + String.format(doubleItem, notes, key));
        }
        if (value instanceof Integer integer) {
            System.out.println(filedTab + String.format(intItem, notes, key));
        }
        if (value instanceof JSONObject jobj) {
            String className = jsonToJava(jobj.toString(), num + 1, isModel, key);
            System.out.println(filedTab + String.format(objItem, notes, className, key));
        }
        if (value instanceof JSONArray jarray) {
            if (CollUtil.isEmpty(jarray)) {
                System.out.println(filedTab + String.format(arrayItem, notes, "Demo" + (++num), key));
            }
            Object o = jarray.get(0);
            if (o instanceof String str) {
                System.out.println(filedTab + String.format(arrayItem, notes, "String", key));
            }
            if (o instanceof BigDecimal bigDecimal) {
                System.out.println(filedTab + String.format(arrayItem, notes, "Double", key));
            }
            if (o instanceof Integer integer) {
                System.out.println(filedTab + String.format(arrayItem, notes, "Integer", key));
            }
            if (o instanceof JSONObject) {
                String className = jsonToJava(o.toString(), num + 1, isModel, key);
                System.out.println(filedTab + String.format(arrayItem, notes, className, key));
            }
            if (o instanceof JSONArray) {
                throw new RuntimeException("我靠 数组嵌套我靠");
            }
        }
    }


}
